using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Windows.Markup;
using System.ComponentModel;
using System.Xml;
using System.IO;
using ViewOnCore.Helper.WPF;
using ViewOn.Kernel;
using ViewOn.Properties;
using ViewOn.AddInsHostContract;
using ViewOn.AddInsHostContract.Media;
using ViewOn.Helper.WPF;
using ViewOnCore.HostContract.Media;
using ViewOnCore.Device;
using ViewOnCore.HostContract;

namespace ViewOn.UI.VisualModeContainer
{

    public partial class MediaDeviceControl : System.Windows.Controls.UserControl
    {

        #region Variables

        private MediaDevice _device;

        private TreeViewItem _contextMenuItem;
        private TreeViewItem _editingMenuItem;
        private DockPanel _normalHeader;

        #endregion

        #region Constructor

        public MediaDeviceControl(MediaDevice device)
        {
            InitializeComponent();
            _device = device;

            //---- Header
            headerText.Text = _device.Title;
            headerImage.Source = new BitmapImage(device.ImageUri);

            //---- Add entries for each feature
            foreach (MediaFeature feature in _device.MediaFeatures)
            {
                TreeViewItem treeViewItem = CreateMediaDeviceFeatureControl(feature.ImageUri, feature.Handle, feature);
                tvDevices.Items.Add(treeViewItem);

                // Sub elements (Play lists, bookmarks...)
                if (feature.HasMediaItems)
                {
                    feature.OnLoadOnDemand();
                    foreach (MediaItem featureItem in feature.MediaItems)
                    {
                        TreeViewItem item = CreateMediaDeviceFeatureItemControl(featureItem);
                        treeViewItem.Items.Add(item);
                    }

                    tvDevices.AddHandler(TreeView.MouseLeftButtonDownEvent, new MouseButtonEventHandler(treeView_MouseLeftButtonDown), true);

                    treeViewItem.IsExpanded = true;
                }
            }

            //---- Is default feature ?
            if (device.IsActive)
                ((TreeViewItem)tvDevices.Items[0]).IsSelected = true;

            //---- Drag & Drop
            tvDevices.DragOver += new DragEventHandler(tvDevices_DragOver);
            tvDevices.Drop += new DragEventHandler(tvDevices_Drop);

            //---- Play list events
            Host.MediaService.MediaDeviceActivation += new EventHandler(MediaService_MediaDeviceActivation);
            Host.MediaService.MediaItemOperation += new MediaItemOperationEventHandler(MediaService_MediaItemOperation);

            //----
            tvDevices.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(tvDevices_SelectedItemChanged);
            tvDevices.AddHandler(TreeViewItem.PreviewMouseRightButtonDownEvent, new MouseButtonEventHandler(tvDevices_MouseRightButtonDown));
        }

        #endregion

        #region CreateMediaDeviceFeatureControl

        private TreeViewItem CreateMediaDeviceFeatureControl(Uri imageUri, string title, MediaFeature feature)
        {
            string xaml = "<TreeViewItem Style=\"{DynamicResource TreeViewItem.TransparentWithEffect4}\"";
            xaml += " xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"";
            xaml += " xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"";
            xaml += " xmlns:wpf=\"clr-namespace:ViewOnCore.Helper.WPF;assembly=ViewOnCore\"";
            xaml += " Foreground=\"{DynamicResource VOColor1A}\">";
            xaml += "<TreeViewItem.Header>";
            xaml += "<DockPanel>";
            xaml += "<wpf:Icon Source=\"" + imageUri.ToString() + "\" Width=\"18\" Height=\"18\"/>";
            xaml += "<TextBlock Margin=\"3,0,3,0\" FontWeight=\"Normal\" VerticalAlignment=\"Center\" Text=\"" + title + "\"/>";
            xaml += "</DockPanel>";
            xaml += "</TreeViewItem.Header>";

            if (feature.HasMediaItems)
            {
                xaml += "<TreeViewItem.ContextMenu>";
                xaml += "<ContextMenu >";
                xaml += "<MenuItem Header=\"" + Globalization.MediaDeviceControl_AddPlayList + "\"></MenuItem>";
                xaml += "</ContextMenu>";
                xaml += "</TreeViewItem.ContextMenu>";
            }

            xaml += "</TreeViewItem>";

            StringReader stringReader = new StringReader(xaml);
            XmlReader xmlReader = XmlTextReader.Create(stringReader, new XmlReaderSettings());

            TreeViewItem item = (TreeViewItem)XamlReader.Load(xmlReader);

            if (item.ContextMenu != null)
                ((MenuItem)item.ContextMenu.Items[0]).Click += new RoutedEventHandler(AddMediaDeviceFeatureItem_Click);

            item.Tag = feature;

            return item;
        }

        #endregion

        #region CreateMediaDeviceFeatureItemControl

        private TreeViewItem CreateMediaDeviceFeatureItemControl(MediaItem mediaDeviceFeatureItem)
        {
            string xaml = "<TreeViewItem Style=\"{DynamicResource TreeViewItem.TransparentWithEffect4}\"";
            xaml += " xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"";
            xaml += " xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"";
            xaml += " xmlns:wpf=\"clr-namespace:ViewOnCore.Helper.WPF;assembly=ViewOnCore\"";
            xaml += " Foreground=\"{DynamicResource VOColor1A}\">";
            xaml += "<TreeViewItem.Header>";
            xaml += "<DockPanel>";
            xaml += "<wpf:Icon Source=\"" + mediaDeviceFeatureItem.ImageUri + "\" Width=\"18\" Height=\"18\"/>";
            xaml += "<TextBlock Margin=\"3,0,3,0\" FontWeight=\"Normal\" VerticalAlignment=\"Center\" Text=\"" + mediaDeviceFeatureItem.Handle + "\"/>";
            xaml += "</DockPanel>";
            xaml += "</TreeViewItem.Header>";

            xaml += "<TreeViewItem.ContextMenu>";
            xaml += "<ContextMenu >";
            xaml += "<MenuItem Header=\"" + Globalization.MediaDeviceControl_RenamePlayList + "\"></MenuItem>";
            xaml += "<MenuItem Header=\"" + Globalization.MediaDeviceControl_DeletePlayList + "\"></MenuItem>";
            xaml += "</ContextMenu>";
            xaml += "</TreeViewItem.ContextMenu>";

            xaml += "</TreeViewItem>";

            StringReader stringReader = new StringReader(xaml);
            XmlReader xmlReader = XmlTextReader.Create(stringReader, new XmlReaderSettings());

            TreeViewItem item = (TreeViewItem)XamlReader.Load(xmlReader);

            ((MenuItem)item.ContextMenu.Items[0]).Click += new RoutedEventHandler(RenameMediaDeviceFeatureItem_Click);
            ((MenuItem)item.ContextMenu.Items[1]).Click += new RoutedEventHandler(DeleteMediaDeviceFeatureItem_Click);

            item.Tag = mediaDeviceFeatureItem;

            return item;
        }

        #endregion

        #region Properties

        public MediaDevice MediaDevice
        {
            get
            {
                return _device;
            }
        }

        #endregion

        #region MediaService : MediaDeviceActivation

        void MediaService_MediaDeviceActivation(object sender, EventArgs e)
        {
            //---- Not for this control
            if (_device == Host.MediaService.CurrentMediaDevice)
            {
                Dispatcher.Invoke(DispatcherPriority.Normal,
                    (DelegateInvoker)delegate { AsyncActivate(); });
            }
            else
            {
                Dispatcher.Invoke(DispatcherPriority.Normal,
                    (DelegateInvoker)delegate { AsyncDeactivate(); });
            }
        }

        /// <summary>
        /// When we double click on a file or a link, viewon is opened
        /// and the activation for the right device is done, but it is
        /// possible that the treeview item is not correctly selected.
        /// </summary>
        private void AsyncActivate()
        {
            ////---- Check that 
            //if (Host.MediaService.CurrentMediaDeviceFeatureItem == null)
            //{
            //    foreach (TreeViewItem item in tvDevices.Items)
            //        if (item.Tag == Host.MediaService.CurrentMediaDevice)
            //            if (tvDevices.SelectedItem != item)
            //                item.IsSelected = true;
            //    return;
            //}

            if (Host.MediaService.CurrentMediaDevice == null)
                return;

            if (Host.MediaService.CurrentMediaDevice != _device)
                return;

            tvDevices.SelectedItemChanged -= new RoutedPropertyChangedEventHandler<object>(tvDevices_SelectedItemChanged);

            //---- Feature
            foreach (TreeViewItem featureItem in tvDevices.Items)
                if (featureItem.Tag == Host.MediaService.CurrentMediaDeviceFeature)
                {
                    if (Host.MediaService.CurrentMediaDeviceFeatureItem == null && tvDevices.SelectedItem != featureItem)
                        featureItem.IsSelected = true;

                    //---- Item
                    foreach (TreeViewItem itemItem in featureItem.Items)
                        if (itemItem.Tag == Host.MediaService.CurrentMediaDeviceFeatureItem)
                        {
                            if (tvDevices.SelectedItem != itemItem)
                                itemItem.IsSelected = true;

                            break;
                        }

                    break;
                }

            tvDevices.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(tvDevices_SelectedItemChanged);
        }

        /// <summary>
        /// Remove the selection of the other tree view items.
        /// </summary>
        private void AsyncDeactivate()
        {
            tvDevices.SelectedItemChanged -= new RoutedPropertyChangedEventHandler<object>(tvDevices_SelectedItemChanged);

            foreach (TreeViewItem item in tvDevices.Items)
            {
                item.IsSelected = false;
                foreach (TreeViewItem subItem in item.Items)
                    subItem.IsSelected = false;
            }

            tvDevices.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(tvDevices_SelectedItemChanged);
        }

        #endregion

        #region Selection

        void tvDevices_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (tvDevices.SelectedItem == null)
                return;

            TreeViewItem item = tvDevices.SelectedItem as TreeViewItem;

            TreeViewItem deviceTreeViewItem = item;

            //-- Define the new device activation
            MediaDevice newMediaDevice = null;
            MediaFeature newFeature = null;
            MediaItem newFeatureItem = null;

            newMediaDevice = _device;
            if (item.Tag is MediaFeature)
            {
                newFeatureItem = null;
                newFeature = item.Tag as MediaFeature;
            }
            else if (item.Tag is MediaItem)
            {
                newFeatureItem = item.Tag as MediaItem;
                newFeature = newFeatureItem.MediaFeature;
            }

            //---- Notify the new activation
            Host.MediaService.ActivateMediaDevice(newMediaDevice,
                                                                    newFeature,
                                                                    newFeatureItem);
        }

        #endregion

        #region MediaService : MediaItemOperation

        void MediaService_MediaItemOperation(MediaFeature feature, MediaOperationKind operationKind, MediaItem featureItem)
        {
            if (operationKind == MediaOperationKind.Added)
                OnMediaItemAdded(featureItem);
            else
                OnMediaItemRemoved(featureItem);

        }

        private void OnMediaItemRemoved(MediaItem featureItem)
        {
            // Not for this device
            if (featureItem.MediaFeature.MediaDevice != _device)
                return;

            foreach (TreeViewItem treeViewItem in tvDevices.Items)
                if (treeViewItem.Tag.Equals(featureItem.MediaFeature))
                    foreach (TreeViewItem subTreeViewItem in treeViewItem.Items)
                        if (subTreeViewItem.Tag.Equals(featureItem))
                        {
                            treeViewItem.Items.Remove(subTreeViewItem);
                            return;
                        }
        }

        private void OnMediaItemAdded(MediaItem featureItem)
        {
            TreeViewItem mediaDeviceFeatureTreeViewItem = null;

            // Not for this device
            if (featureItem.MediaFeature.MediaDevice != _device)
                return;

            foreach (TreeViewItem treeViewItem in tvDevices.Items)
                if (treeViewItem.Tag.Equals(featureItem.MediaFeature))
                {
                    mediaDeviceFeatureTreeViewItem = treeViewItem;
                    break;
                }

            TreeViewItem item = CreateMediaDeviceFeatureItemControl(featureItem);
            mediaDeviceFeatureTreeViewItem.Items.Add(item);

            item.IsSelected = true;

            StartTreeEditing(item);
        }

        #endregion

        #region Contextual Menu

        void AddMediaDeviceFeatureItem_Click(object sender, RoutedEventArgs e)
        {
            MediaFeature feature = _contextMenuItem.Tag as MediaFeature;
            feature.CreateNewMediaItem();
        }

        void DeleteMediaDeviceFeatureItem_Click(object sender, RoutedEventArgs e)
        {
            MediaItem featureItem = _contextMenuItem.Tag as MediaItem;
            featureItem.MediaFeature.RemoveMediaItem(featureItem);
        }

        void RenameMediaDeviceFeatureItem_Click(object sender, RoutedEventArgs e)
        {
            StartTreeEditing(_contextMenuItem);
        }

        #endregion

        #region TreeView edition

        private void StartTreeEditing(TreeViewItem editingMenuItem)
        {
            if (_normalHeader != null)
                StopTreeEditing(true); // Stop with the previous editing node

            // Now use the new node
            _editingMenuItem = editingMenuItem;

            TextBox txtEditor = new TextBox();
            txtEditor.Text = ((PlayList)_editingMenuItem.Tag).Handle;
            txtEditor.KeyDown += new KeyEventHandler(txtEditor_KeyDown);
            txtEditor.LostFocus += new RoutedEventHandler(txtEditor_LostFocus);

            _normalHeader = (DockPanel)_editingMenuItem.Header;
            _editingMenuItem.Header = txtEditor;

            // Get focus and get all
            txtEditor.UpdateLayout(); // Needed !! refresh the IsVisible property
            txtEditor.SelectAll();
            txtEditor.Focus();
        }

        private void StopTreeEditing(bool validate)
        {
            if (_editingMenuItem == null)
                return;

            if (!(_editingMenuItem.Tag is MediaItem))
                return;

            TextBox txtEditor = (TextBox)_editingMenuItem.Header;
            txtEditor.KeyDown -= new KeyEventHandler(txtEditor_KeyDown);
            txtEditor.LostFocus -= new RoutedEventHandler(txtEditor_LostFocus);

            if (validate)
            {
                ((PlayList)_editingMenuItem.Tag).Handle = txtEditor.Text;
                ((TextBlock)_normalHeader.Children[1]).Text = txtEditor.Text;
            }

            _editingMenuItem.Header = _normalHeader;
            _normalHeader = null;
            _editingMenuItem = null;
        }

        void tvDevices_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e != null)
                _contextMenuItem = TreeViewHelper.SearchAncestorTreeViewItem(e.Source);
        }

        void treeView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount != 2)
                return;

            _contextMenuItem = TreeViewHelper.GetTreeViewItemFromChild(e.OriginalSource as DependencyObject);
            if (_contextMenuItem == null)
                return;

            if ((_contextMenuItem.Tag as PlayList) == null)
                return;

            StartTreeEditing(_contextMenuItem);
        }

        void txtEditor_LostFocus(object sender, RoutedEventArgs e)
        {
            StopTreeEditing(true);
        }

        void txtEditor_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
                StopTreeEditing(true);
            else if (e.Key == Key.Escape)
                StopTreeEditing(false);
        }

        #endregion

        #region Drag & Drop

        void tvDevices_DragOver(object sender, DragEventArgs e)
        {
            e.Handled = true;
            e.Effects = DragDropEffects.Move;

            if (e.Data.GetFormats().Length < 1)
                return;

            Point mousePosition = MouseUtilities.GetMousePosition(tvDevices);
            TreeViewItem item = TreeViewHelper.GetTreeViewItemAtLocation(tvDevices, mousePosition) as TreeViewItem;

            if (item == null)
                return;

            //---- Search for a handler
            MediaFeature feature = item.Tag as MediaFeature;
            MediaItem featureItem = null;
            if (feature == null)
            {
                featureItem = item.Tag as MediaItem;
                feature = featureItem.MediaFeature;
            }

            if (Host.MediaService.CanCopyMediaDatas(feature, featureItem))
            {
                e.Effects = DragDropEffects.Copy;
                return;
            }
        }

        void tvDevices_Drop(object sender, DragEventArgs e)
        {
            Point mousePosition = MouseUtilities.GetMousePosition(tvDevices);
            TreeViewItem item = TreeViewHelper.GetTreeViewItemAtLocation(tvDevices, mousePosition) as TreeViewItem;
            if (item == null)
                return;

            MediaFeature feature = item.Tag as MediaFeature;
            MediaItem featureItem = null;
            if (feature == null)
            {
                featureItem = item.Tag as MediaItem;
                feature = featureItem.MediaFeature;
            }

            List<MediaData> sourceMusics = e.Data.GetData(typeof(MediaData).FullName) as List<MediaData>;

            // Search for a handler able to handle it
            Host.MediaService.CopyMediaDatas(sourceMusics, feature, featureItem);

            e.Effects = DragDropEffects.Copy;
            e.Handled = true;
        }

        #endregion

    }
}